package com.jeesite.modules.digitalize.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jeesite.modules.digitalize.util.mpp.MppUtil;
import com.jeesite.modules.digitalize.util.mpp.TaskInfoVo;
import com.jeesite.modules.digitalize.util.response.ResultVo;
import com.jeesite.modules.digitalize.dao.DigitalizePlanDao;
import com.jeesite.modules.digitalize.entity.DigitalizePlan;
import com.jeesite.modules.digitalize.entity.DigitalizePlanDetail;
import net.sf.mpxj.Duration;
import net.sf.mpxj.ProjectFile;
import net.sf.mpxj.Task;
import net.sf.mpxj.writer.ProjectWriter;
import net.sf.mpxj.writer.ProjectWriterUtility;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * (DigitalizePlan)表服务实现类
 *
 * @author mxz
 * @since 2023-11-13 17:55:30
 */
@Service("digitalizePlanService")
public class DigitalizePlanService extends ServiceImpl<DigitalizePlanDao, DigitalizePlan> {
    @Resource
    DigitalizePlanDetailService digitalizePlanDetailService;
    @Lazy
    @Resource
    DigitalizeTaskService digitalizeTaskService;

    @Transactional
    public ResultVo<Boolean> delete(List<Long> idList) {
        digitalizePlanDetailService.lambdaUpdate().in(DigitalizePlanDetail::getPlanId, idList).remove();
        List<Long> taskIdList = digitalizePlanDetailService.lambdaQuery().select(DigitalizePlanDetail::getTaskId).in(DigitalizePlanDetail::getPlanId, idList).list().stream().map(DigitalizePlanDetail::getTaskId).collect(Collectors.toList());
        digitalizeTaskService.delete(taskIdList);
        return ResultVo.success(this.removeByIds(idList));
    }

    /**
     * 导入计划
     *
     * @param id   计划id
     * @param file 文件
     * @return ResultVo<Object>
     */
    @Transactional
    public ResultVo<Object> importPlan(Long id, MultipartFile file) {
        List<TaskInfoVo> taskInfoVoList = MppUtil.analysisMpp(file);
        if (CollUtil.isEmpty(taskInfoVoList)) {
            return ResultVo.failure("导入失败");
        }
        String name = FileUtil.getName(file.getOriginalFilename());
        //替换后缀名
        if (name != null) {
            name = name.substring(0, name.lastIndexOf("."));
        }
        this.lambdaUpdate().eq(DigitalizePlan::getId, id).set(DigitalizePlan::getPlanName, name).update();
        digitalizePlanDetailService.lambdaUpdate().eq(DigitalizePlanDetail::getPlanId, id).remove();
        List<Long> taskIdList = digitalizePlanDetailService.lambdaQuery().select(DigitalizePlanDetail::getTaskId).eq(DigitalizePlanDetail::getPlanId, id).list().stream().map(DigitalizePlanDetail::getTaskId).collect(Collectors.toList());
        digitalizeTaskService.delete(taskIdList);
        //按照层级保存
        Map<Integer, List<TaskInfoVo>> listMap = taskInfoVoList.stream().collect(Collectors.groupingBy(TaskInfoVo::getParentId));
        importPlanSave(id, listMap, 0, 0L);
        return ResultVo.success();
    }

    /**
     * 导入数据保存
     *
     * @param planId   计划id
     * @param listMap  数据集合
     * @param parentId 父id
     * @param dataId   数据库id
     */
    public void importPlanSave(Long planId, Map<Integer, List<TaskInfoVo>> listMap, int parentId, Long dataId) {
        List<TaskInfoVo> taskInfoVoList = listMap.get(parentId);
        if (CollUtil.isEmpty(taskInfoVoList)) {
            return;
        }
        for (int i = 0; i < taskInfoVoList.size(); i++) {
            TaskInfoVo e = taskInfoVoList.get(i);
            DigitalizePlanDetail detail = new DigitalizePlanDetail()
                    .setPlanId(planId)
                    .setParentId(dataId)
                    .setName(e.getTaskName())
                    .setSequence(i + 1)
                    .setPlanStartDate(e.getTaskStartDate())
                    .setPlanEndDate(e.getTaskFinishDate())
                    .setStartDate(e.getActualStart())
                    .setEndDate(e.getActualFinish());
            digitalizePlanDetailService.save(detail);
            importPlanSave(planId, listMap, e.getTaskId(), detail.getId());
        }
    }

    public void exportPlan(Long id, HttpServletResponse response) {
        DigitalizePlan digitalizePlan = this.getById(id);
        if (digitalizePlan == null) {
            throw new RuntimeException("计划不存在");
        }
        List<DigitalizePlanDetail> list = digitalizePlanDetailService.traverseDeep(id);
        if (CollUtil.isEmpty(list)) {
            throw new RuntimeException("导出失败");
        }
        try {
            String fileName = digitalizePlan.getPlanName() + ".xml";
            // 设置响应头，控制浏览器下载该文件
            response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            ProjectWriter writer = ProjectWriterUtility.getProjectWriter(fileName);
            ProjectFile projectFile = new ProjectFile();
            buildTask(projectFile, list, 1);
            writer.write(projectFile, response.getOutputStream());
        } catch (Exception e) {
            log.error("Project导出失败", e);
            throw new RuntimeException("Project导出失败");
        }
    }

    private void buildTask(ProjectFile projectFile, List<DigitalizePlanDetail> list, int level) {
        if (CollUtil.isNotEmpty(list)) {
            list.forEach(e -> {
                Task task = projectFile.addTask();
                task.setName(e.getName());
                task.setOutlineLevel(level);
                task.setDuration(Duration.getInstance(DateUtil.betweenDay(e.getPlanStartDate(), e.getPlanEndDate(), false) + 1, net.sf.mpxj.TimeUnit.DAYS));
                task.setStart(e.getPlanStartDate());
                task.setFinish(e.getPlanEndDate());
                task.setActualStart(e.getStartDate());
                task.setActualFinish(e.getEndDate());
                task.setActualDuration(Duration.getInstance(DateUtil.betweenDay(e.getStartDate(), e.getEndDate(), false) + 1, net.sf.mpxj.TimeUnit.DAYS));
                if (CollUtil.isNotEmpty(e.getChildrenList())) {
                    buildTask(projectFile, e.getChildrenList(), level + 1);
                }
            });
        }
    }

    public Long getComponentIdByPlanDetailId(Integer planDetailId) {
        return this.baseMapper.getComponentIdByPlanDetailId(planDetailId);
    }
}

